# -*- coding:utf-8 -*-
"""
Created on 2010-1-20

@author: Administrator
@summary: 
@version: 
@todo: 
1. vest port and relation physics attribute
2. hyper-graph connected component, find path. 
3. associate trans with hyper-graph 
4. state tracking

@change: 
change class Node from parent to neighbors and friends

@attention: 
test if id of class A and class B is equal, use id(A)==id(B)
test if class A and class B is equal, use A==B. just as lista==listb or dicta==dictb

@attention:
when copy a instance, should use copy.copy(instance).    
"""


from random import randint
from time import time
import copy


def randid():
    return str(randint(1, int(time())))

class Port:
    '''
    physics system used!
    describe the moudle's port
    '''
    def __init__(self, name, *attr): #attr is dict type
        ''' 
        @var accessible: 0 stands for the relation which contains the Port actually is not exists
            (valid/avaible/accessible/visible/reachable)
        @var state: describe the instance is changed or not
        @var module: describe the port belongs to which module
        @var nValue: velocity of revolution / flow / current
        @var mValue: Torque / flux / voltage
        @var stage: 1/2/3 stands for mechanical/fluid/gaseity
        @var isSource: if the source
        @var isCalculated: flag the port is calculated or not
        '''
        self.name = name
        self.accessible = 1
        self.attr = attr
        self.module = None
#        self.id = randid()
        self.id = id(self)
        self.state = 0
        
        self.nValue = 0
        self.mValue = 0
        self.stage = 1
        self.isSource = False
        self.isCalculated = False
        
    def setnValue(self, value, isSource):
        self.nValue = value
        self.isSource = isSource
        self.isCalculated = True
    
    def setmValue(self, value, isSource):
        self.mValue = value
        self.isSource = isSource
        self.isCalculated = True
    
    def stateChanged(self):
        return self.state
        
    def updateModule(self, module):
        self.module = module

#    def isMember(self,other):
#        '''
#        test if this module and other module has the same module 
#        '''
#        return self.module == other.module
    
#    def update(self):
#        self.id = id(self)
    
    def setAccessible(self, accessible):
        if self.accessible != accessible:
            self.accessible = accessible
            self.state = 1
    
    def __eq__(self, other):
        return self.module == other.module and self.name == other.name
#        return id(self) == id(other)

    def __lt__(self, other):
        '''
        used in the sort() function
        '''
        return self.module == other.module and self.name < self.name
    
    def getAttr(self):
        return self.attr
    
    def isAccessible(self):
        return self.accessible
        
    def __repr__(self):
        '''
        represent Port's name
        '''
        return repr(self.module.name + '.' + self.name)
#        return repr({self.name:(self.accessible,self.attr)})

class Relation: 
    '''
    physics system used!
    self-loop relation: one port
    normal relation: two ports
    tri-relations: three ports or more 
    inside or beside the same module,constructed from port.
    '''
    def __init__(self, *ports):
        '''
        @param ports: []
        @var stage: the type of relation itself, for example:
                    0 - relation acted as converter
                    1 - relation is mechical
                    2 - relation is flue
                    3 - relation is electric
        @var virtual: the type of relation resulting in ports, for example:
                    False - relation is normal
                    True - relation is actually not exists
        '''
        self.id = id(self)
        self.stage = 1
        self.virtual = False
        name = ''
        self.ports = {}  #[]? todo!
#        reality = 1
        for port in ports:
            name += '_' + port.module.name + '.' + port.name
            self.ports.update({port.id:port})
#            self.ports[port.id] = port
        self.name = name[1:]
        self.state = 0
        self.formula = ''
        self.interior = True
    
    def isInterior(self):
        '''
        test if the relation is interior or outer
        '''
        if self.state:
            interior = True
            num = len(self.ports)
            base = self.ports[0]
            i = 1
            while i < num:
                if base.module != self.ports[i].module:
                    interior = False
                    break
                i += 1
            self.interior = interior
        return self.interior
       
    def setFormula(self, formula):
        self.formula = formula
        self.state = 1
    
    def __eq__(self, other):
        '''
        test if the relation associate the ports equals to other or not
        '''
#        a = self.ports.values()
#        a.sort()
#        b = other.ports.values()
#        b.sort()
#        return a == b
        return self.ports == other.ports and self.formula == other.formula
        
    def stateChanged(self):
        state = 0
        for port in self.ports.values():
            state += port.stateChanged()
        return state + self.state
    
    def isVirtual(self):
        #@note: the type of ports which the relation containing must be 1 
        #@see: port::type
        if self.stateChanged():
            for port in self.ports.values():
                self.virtual &= port.accessible
        return self.virtual
        
    def hasPort(self, ports):
        '''
        relatioin containing port or not. 
        @param port: {} 
        '''
        isContain = 0
        for port in ports.values():
            isContain += self.ports.has_key(port.id)
        return isContain
        
    def update(self):
        name = ''
        for port in self.ports.values():
            name += '_' + port.module.name + '.' + port.name
        self.name = name[1:]

    def setStage(self, stage):
        '''
        the type of relation, for example:
        0 stands for the relation is actually not exists
        1 - mech
        2 - flow
        3 - elec         
        '''
        self.stage = stage
        self.state = 1
               
#    def updateModule(self,module):    
#        '''
#        update module info into relation
#        '''
#        ports = []
#        name = ''
#        for port in self.ports:
#            name += module.name + '.' + port[1].name + '_'
#            ports.append((module,port))
#        self.name = name[0:-1]
#        self.ports = ports
                
      
    def setName(self, name):
        self.name = name
        
    def __repr__(self):
        '''
        represent relation name
        '''
        return repr(self.name)
#        return repr(self.ports)
        
class Module:
    '''
    module play a part in tranmission and converter!
    so relations in the same module are figured out with formula,
    while relations between modules can express with the ports stage, because of its just transmission action
    
    one module contains ports and relations.
    when construct a module, suggest as the follow:
    1. construct ports
    2. construct a moudle
    3. add nRelations and mRelations into module
    '''
    
    def __init__(self, *ports):
        '''
        ports is a dict
        nRelations is a dict
        mRelations is a dict
        '''
        self.id = id(self)
        self.name = randid()
        self.ports = {}
        for port in ports:
            port.updateModule(self)
            self.ports[port.id] = port
        self.nRelations = {}
        self.mRelations = {}
#        self.iswork = True
        self.control = 0 # the default control state. control is one set of many states
        self.state = 0 #state 0 - non change; 1 - changed!
    
#    def __eq__(self, other):
#        pa = self.ports.values()
#        pa.sort()
#        pb = other.ports.values()
#        pb.sort()
#        na = self.nRelations.values()
#        na.sort()
#        nb = other.nRelations.values()
#        nb.sort()
#        ma = self.mRelations.values()
#        ma.sort()
#        mb = other.mRelations.values()
#        mb.sort()
#        return pa == pb and na == nb and ma == mb
#        return self.ports == other.ports and self.nRelations == other.nRelations and self.mRelations == other.mRelations
        
#    def update(self):
#        '''
#        update module info into ports, relations
#        should use before addnRelation and addmRelations, that is the object of module is __init__ done!
#        '''
##        ports = {}
##        for port in ports:
##            port.module = self
##            self.ports[port.name] = port
##        self.ports = ports
##        for i in range(len(self.ports)):
##            self.ports[i].module = self
#        for i in range(len(self.ports)):
#            self.ports[i].updateModule(self)
#
#                
#    def updateAfter(self):
#        for i in range(len(self.ports)):
#            self.ports[i].module = self
#        for i in range(len(self.nRelations)):
#            for j in range(len(self.nRelations[i].ports)):
#                self.nRelations[i].ports[j].module = self 
                          
    def addnRelations(self, *relations):
        self.state = 1
        for relation in relations:
#            relation.updateModule(self)
            self.nRelations[relation.id] = relation
#            self.stateChanged = True

    def removenRelations(self):
        self.state = 1
        self.nRelations = {}
    
    def addmRelations(self, *relations):
        self.state = 1
        for relation in relations:
#            relation.updateModule(self)
            self.mRelations[relation.id] = relation
#            self.stateChanged = True
    
    def removemRelations(self):
        self.state = 1
        self.mRelations = {}
    
    def getPort(self, name):
        '''
        name, not id!
        '''
#        self.state = 0
        for port in self.ports.keys():
            if(self.ports[port].name == name):
                return self.ports[port]
        return None  #can not find the port named 'name' 
  
    def getPorts(self):
        return self.ports
    
#    def getnRelation(self,name):
#        self.state = 0
#        return self.nRelations[name]
#    
#    def getmRelation(self,name):
#        self.state = 0
#        return self.mRelations[name]
    
#    def removenRelation(self):
#        self.nRelations = []
#    
#    def removemRelation(self):
#        self.mRelations = []
#    
    def setName(self, name):
        self.name = name
        for relation in self.nRelations.keys():
            self.nRelations[relation].update()
        
    
    def setControl(self, control):
        if self.control != control:
            self.control = control
            self.state = 1
            
    def stateChanged(self):
        return self.state

    def __repr__(self):
        '''
        represent module's struct
        '''
        return repr((self.name, self.ports, self.nRelations))
#        port = []
#        nRelations = []
#        for v in self.ports.values():
#            port.append(v.name)
#        for e in self.nRelations.values():
#            nRelations.append(e.name)
#        return repr((port,nRelations))

#        return repr((self.ports,self.nRelations,self.mRelations))
    
#    def addPort(self,port):
#        self.ports.append(port)
#        
#    def addPorts(self,ports):
#        self.ports.extend(ports)
#    
#    def removePort(self,port):
#        self.ports.remove(port)
#    
#    def removePorts(self,ports):
#        for port in ports:
#            self.ports.remove(port)


class Trans:
    '''
    one transmission contains more modules and relations
    '''
    
    def __init__(self, *modules):
        '''
        modules is a dict
        @var relations: describe the relations between modules. 
        nRelations is a dict
        mRelations is a dict
        '''
        self.id = id(self)
        self.name = randid()
        
        self.modules = {}
        for module in modules:
            self.modules[module.id] = module
        self.relations = {} 
        
        self.nRelations = {}
        self.mRelations = {}
        
        self.state = 0 #flag is used for sign the trans itself's state is changed or not
    
#    def updateRelations(self,module,relation):
#        pass


    def __eq__(self, other):
        return self.modules == other.modules and self.relations == other.relations
            
    def stateChanged(self):
        '''
        used in api
        '''
        state = self.state
        for module in self.modules.keys():
            state += self.modules[module].stateChanged()
        for relation in self.relations.keys():
            state += self.relations[relation].stateChanged()
        return state
    
    def setName(self, name):
        self.name = name
    
    def addModule(self, *modules):  #check the * and ** means for
        self.state = 1
        for module in modules:
#            self.modules[module.keys()[0]] = module.values()[0]
            self.modules[module.id] = module

   
    def getModules(self):
        return self.modules
    
    def removeModule(self, *modules):
        '''
        remove the module and its relation
        '''
        ports = {}
        for module in modules:
            if self.modules.has_key(module.id):
                ports.update(module.ports)
                del self.modules[module.id]
            
        for relation in self.relations.values():
            if relation.hasPort(ports):
                del self.relations[relation.id]
    
    
    def addRelation(self, *relations): #mv equals to (module, port) #between modules
        self.state = 1
        for relation in relations:
            self.relations[relation.id] = relation

     
#    def getRelations(self):
#        return self.relations
    
    def removeRelation(self, *relations):
        '''
        remove the relations
        '''
        for relation in relations:
            if self.relations.has_key(relation.id):
                del self.relations[relation.id]
        
    
    def getPorts(self):
        self.state = 0
        ports = {}
        for module in self.modules.values():
            ports.update(module.getPorts())
        return ports
            
        
    def getnRelations(self):
        if self.stateChanged():
            nRelations = {}
            for relation in self.relations.values():               
                if relation.getReality():
                    nRelations.update({relation.id:relation})
            for module in self.modules.values():
                nRelations.update(module.nRelations)
            self.nRelations = nRelations  #nRelations.copy()
        return self.nRelations
    
    def __repr__(self):
        '''
        represent trans's struct
        '''
        return repr((self.modules, self.relations))




'''
----------------------------  hyper graph --------------------------------
'''
class Node:
    '''
    @summary: Node used in graph! - port  
    '''
    def __init__(self, port):
        '''
        @var port: transmission system.
        @var adj: adjacency edges
        #@var father: should be None, when self only it describe self-loop edge. 
        #@var neighbors: assocate with other nodes within one module.use() stands for hyper-node.
        #@var friends: assocate with other module nodes.
        #@var edges: the associated edges with the port
        '''
        self.port = port 
#        self.father = None
        self.adj = []
#        self.neighbors = []
#        self.friends = []
        self.visited = False
#        self.rank = 1
    
#    def __eq__(self,other):
#        return self.port == other.port
    def equal(self, other):
        return self.port == other.port
    
    def addEdges(self, *edges):
        for edge in edges:
            if self.edges.count(edge):
                self.edges.append(edge)
            
    def removeRelation(self, *edges):
        for edge in edges:
            if self.edges.count(edge):
                self.edges.remove(edge)
    
    def isMember(self, other):
        return self.port.module == other.port.module
    
#    def addFriends(self, nodes):
#        '''
#        @summary: add friend nodes into self.friends. 
#            addFriends(1,2,3), then self.friends.extends((1,2,3))
#        @param nodes: when type is tuple, meaning that the assocate edge is triple edge
#        '''
#        if isinstance(nodes, tuple):
#            self.friends.append(nodes)
#        else:
#            self.friends.extend(nodes)
#        
#    def addNeighbors(self, neighbors):
#        if isinstance(neighbors, tuple):
#            self.neighbors.append(neighbors)
#        else:
#            self.neighbors.extend(neighbors)
#        
#    def removeFriends(self, nodes):
#        if isinstance(nodes, list):
#            for node in nodes:
#                if self.friends.count(node):
#                    self.friends.remove(node)
#                    break
#        else:
#            if self.friends.count(nodes):
#                self.friends.remove(nodes)
#    
#    def removeNeighbors(self, neighbors):
#        if isinstance(neighbors, list):
#            for neighbor in neighbors:
#                if self.neighbors.count(neighbor):
#                    self.neighbors.remove(neighbor)
#                    break
#        else:
#            if self.neighbors.count(neighbors):
#                self.neighbors.remove(neighbors)
#    
    
#    def setNeighbors(self,*neighbors):
#        self.neighbors = list(neighbors)
        
    def toPort(self):
        return self.port
    
    def __repr__(self):
#        return repr((self.father.port,self.port,self.rank))
        return repr(self.port)

class Edge:
    '''
    @summary: Edge used in graph. - relation
    '''
    def __init__(self, relation):
        '''
        #@var type: describe the type of the relation. 0 -- inside edge. 1 -- outside edge
        '''
        self.relation = relation
        self.nodes = []
#        self.type = type
        for port in relation.ports.values():
            node = Node(port)
            node.addEdges(self)
            self.nodes.append(node)
        self.interior = self.isInterior()
#        self.status = 0
#        self.update('add')
    
    def extend(self,edge):
        '''
        extends the edge with other edge, just used between modules.
        '''
        pass
    
    def append(self,relation):
        '''
        extends edge with other relation, just used between modules.
        '''
        pass
    
#    def __init__(self, relation, nodes, type):
#        '''
#        @summary: init edge from relation and nodes, avoid from recreate the node
#        @param relation: 
#        @param nodes: nodes which has constructed
#        @param type: inside module when type=0, between modules when type=1
#        '''
#        self.relation = relation
#        self.nodes = []
#        self.type = type
#        for port in relation.ports.values():
#            has = False
#            for node in nodes:
#                if node.toPort() == port:
#                    self.nodes.append(node)
#                    has = True
#                    break
#            if not has:
#                node = Node(port)
#                self.nodes.append(node)
    
#    def update(self, action='add'):
#        '''
#        @summary: update nodes belongs the edge. action is designed for 'add' and 'del'
#                just as union-query-collection merge.
#        @param action: 'add','del'
#        '''
#        for i, n in enumerate(self.nodes):
#            l = []
#            if len(self.nodes) == 1: #self-loop
#                l = self.nodes 
#            else:
#                for j, m in enumerate(self.nodes):
#                    if i != j:
#                        l.append(m)
#                    
#            if self.type: # between modules
#                if action == 'add':
#                    n.addFriends(l)
#                elif action == 'del':
#                    n.removeFriends(l)
#                else:
#                    raise ValueError, 'action value is designed for \'add\' and \'del\'!'
#            else: #inside modules
#                if len(l) > 1:
#                    l = tuple(l)
#                if action == 'add':
#                    n.addNeighbors(l)
#                elif action == 'del':
#                    n.removeNeighbors(l)
#                else:
#                    raise ValueError, 'action value is designed for \'add\' and \'del\'!'
    
    def isInterior(self):
        interior = True
        num = len(self.nodes)
        base = self.nodes[0]
        i = 1
        while i < num:
            if not base.isMember(self.nodes[i]):
                interior = False
                break
            i += 1
        return interior
    
    def getFirstNode(self):
        return self.nodes[0]
    
    def getNextNode(self, node):
        n = 0
        while n < len(self.nodes):
            if self.nodes[n] == node:
                break
            n += 1
        if n < len(self.nodes):
            return self.nodes[n]
        return None
        
            
    def hasNode(self, node):
        '''
        @summary: test if the edge contains node or not
        '''
        return self.nodes.count(node)
#        for n in self.nodes:
##            if n.port==node.port: #ugly! todo!
#            if n==node:
#                return True
#        return False
    
    def toRelation(self):
        return self.relation
        
    def __repr__(self):
        return repr(self.nodes)
    
class HGraph:
    '''
    hyper graph. - trans
    '''
    def __init__(self, trans):
        self.trans = trans
        self.nodes = []
        self.nEdges = []
        self.mEdges = []
#        self.connectComponents = []
        self.__toHGraph()
        self.status = 0
    
    def setTrans(self, trans):
        self.trans = trans
        
    def __toHGraph(self):
        '''
        translate trans into hyper-graph. todo!
        '''
        for module in self.trans.modules.values():
            for port in module.ports.values():
                self.nodes.append(Node(port))
                
        for relation in self.trans.relations.values():
            if relation.getReality():
                self.nEdges.append(Edge(relation))
#                self.mEdges = self.mergeInto(Edge(relation, 1), self.mEdges)
            
        for module in self.trans.modules.values():
            for relation in module.nRelations.values():
                self.nEdges.append(Edge(relation))
            for relation in module.mRelations.values():
                self.mEdges.append(Edge(relation))
        
#        for edge in self.nEdges:
#            edge.update('add')

    def findnPath(self, src, dest):
        for edge in self.nEdges:
            if edge.isInterior(): #the relation inside one module
                pass 
        
    def update(self):
        '''
        when the relation is changed, refresh the node relations!
        ''' 
        #update module info
        ports = []
        nodes = set()
        for module in self.trans.modules.values():
            for port in module.ports.values():
                ports.append(port)
        for node in self.nodes:
            if not ports.count(node.toPort()):
                self.nodes.remove(node)
            nodes.update(node.toPort())
        adds = set(ports) - nodes
        for node in adds:
            self.nodes.append(Node(node))
        
        
        #update relation info
        for relation in self.trans.relations.values():
            if relation.getReality():
                pass
                   
                
#    def findnPath(self, src, dest, path):
#        '''
#        find revolation relatioship of the trans. use bfs in the hyper-edge, while dfs in others
#        friend first 
#        @param src: source node
#        @param dest: target node 
#        '''
##        for node in self.nodes:
##            pass
#        
##        openset = [src]
##        path = []
##        while openset:
##            s = openset.pop()
##            if s.neighbors:
##                for neighbor in s.neighbors:
##                    l = [s]
##                    path.append(l.extend(neighbor))
##                    if isinstance(neighbor, tuple):
##                        pass
##                    else:
##                        openset.append(neighbor)
##            for friend in s.friends:
##                if isinstance(friend, tuple):
##                    raise ValueError, str(s.friends) + ' has tuple type!'
##                openset.append(friend)
#         
#        l = [src]
#        while l:
#            n = l.pop()
#            n.visited = True
#            for friend in n.friends:
#                if not friend.visited:
#                    self.findnPath(friend, dest) 
#            for neighbor in n.neighbors:
#                if isinstance(neighbor, Node) and not neighbor.visited: #
#                    l.append(neighbor)
#                if isinstance(neighbor, tuple): #hyper-edges
#                    pass
#                
##        while openset:
##            pass

    def connectedComponent(self):
        pass
        
        
    def findnPath2(self, src, dest):
        '''
        neighbor first
        '''
        pass

    def DFS(self, v):
        '''
        depth first search
        '''
        v.visited = True
        for neighbor in v.neighbor:
            if not neighbor.visited:
                self.DFS(neighbor)
                
    def BFS2(self, v):
        '''
        bread first search.
        filo
        '''
        l = [v]
        while l:
            s = l.pop()
            s.visited = True
            for neighbor in s.neighbor:
                if not neighbor.visited:
                    l.append(neighbor)
            
    def BFS(self, v):
        '''
        bread first search.
        fifo
        '''
        l = [v]
        while l:
            s = l[0]
            l.remove(s)
            s.visited = True
            for neighbor in s.neighbor:
                if not neighbor.visited:
                    l.append(neighbor)

    def findmPath(self, node):
        pass
    
    
#    def parseRelations(self):
#        '''
#        translate trans.relations into hgraph mEdges
#        '''
#        for relation in self.trans.relations.values():
#            self.mEdges = self.mergeInto(Edge(relation, self.nodes), self.mEdges)
        
    def mergeInto(self, edge, bases):
        '''
        merge edge into base edges, used in mEdges.
        @param edge: edge
        @param base: [edge1,edge2,...,edgen]
        '''
        newedge = copy.copy(edge)
        newbases = []
        if not bases: #base is []
            return [edge]
        
        for base in bases:
#            has = False
            nodes = []
            for node in edge.nodes:
                if base.hasNode(node):
#                    has = True
                    nodes.append(node)
#                    edge.nodes.remove(node)
            if nodes:
                for node in base.nodes:
                    if not nodes.count(node):
                        newedge.nodes.append(node)
            else:
                newbases.append(base)
        newbases.append(newedge)

        return newbases
        
#        primary = None
#        for node in edge.nodes:
#            for base in bases:
#                if base.hasNode(node):
#                    edge.nodes.remove(node)
#                    if not primary:
#                        primary = base
#                        primary.extend(edge.nodes)
#                    else:
#                        base.remove(node)
#                        primary.extend(base)
#                        bases.remove(base)
#        if not primary:
#            bases.append(edge)
       
        
    def merge(self, *edges):
        '''
        merge two or more edges into one, used in mEdges.
        the first edge is base, if the later edge can merge into the base, then delete the later, return the base, else return themself. 
        '''
        if len(edges) < 2:
#            raise ValueError, 'edges length must be greater than 2 or more'
            return edges
#        base = edges[0]
#        later = edges[1:]
        if edges[0]:
            for node in edges[1].nodes:
                if edges[0].hasNode(node):
                    edges[1].remove(node)
        edges[0].extend(edges[1])
        if len(edges) == 2:
            return edges[0]
        else:
            return self.merge(edges[0], edges[2:])
            
    
    def fatherNode(self, node):
        p = node
        while p.father != p:
            p = p.father
        return p
    
    def getNode(self, port):
        for node in self.nodes:
            if node.port == port:
                return node
    
    def getConnectComponents(self):
        pass
    
    def getPath(self):
        pass
    
    def getCircle(self):
        pass
    
    def getLoop(self):
        pass
    
    def __repr__(self):
        return repr((self.nodes, self.edges))
        
        

#class ConnectedComponet:
#    
#    def __init__(self, trans):
#        self.trans = trans
#        self.cc = []
#        
#    
#    '''
#    m is a module, v is one port, and return the root node of the tree containing port v
#    '''
#    def find(self, port):
#        p = Node(port)
#        while p.father != p:
#            p = p.father
#        return p
#    
#    '''
#    ports length must be equal or  more than 2
#    generally, used in relations and relations
#    and return the merged root node of the tree containing ports
#    
#    verticcs struct is [(module1,port1),(module2,port2),...,(module3,port3)]
#    
#    how about one port self-loop? todo
#    how about 3 or more port? done
#    '''
#    def merge(self, *ports):
#        if len(ports) < 2:
#            print ports
#            raise ValueError, 'ports length must be greater than 2 or more'
#        ports = ports[:]  #copy the ports, because of the parameter ports is passing address
#        v1 = ports.pop()
#        v2 = ports.pop()
#        p1 = self.find(v1)
#        p2 = self.find(v2)
#        if p1.rank >= p2.rank:
#            p2.father = p1
#            if p1.rank == p2.rank:
#                p1.rank += 1
#            if len(ports) > 0:
#                self.merge(p1.mv, ports)
#                return p1
#        elif p1.rank < p2.rank:
#            p1.father = p2
#            if len(ports) > 0:
#                self.merge(p2.mv, ports)
#                return p2
#        
#    '''
#    get all connected components, todo
#    '''
#    def getConnComps(self):
#        if self.trans.stateChanged:
#            p = None
#            for module in self.trans.modules.values():
#                for relation in module.nRelations.values():
#                    if p:
#                        p = self.merge(p, relation.ports)
#                    else:
#                        p = self.merge(relation.ports)
#                    
#            for relation in self.trans.relations.values():
#                if p:
#                    p = self.merge(p.mv, (relation.m1, relation.v1), (relation.m2, relation.v2))
#                else:
#                    p = self.merge((relation.m1, relation.v1), (relation.m2, relation.v2))
#            return p   
#     
#    '''
#    get one port connected component
#    '''
#    def getConnComp(self, mv):
#        p = None
#        for module in self.trans.modules:
#            for relation in module.nRelations:
#                if p:
#                    p = self.merge(p.mv, relation.ports)
#                else:
#                    p = self.merge(relation.ports)
#                
#        for relation in self.trans.relations:
#            if p:
#                p = self.merge(p.mv, relation)
#            else:
#                p = self.merge(relation)
#        
#        return p
#
#    '''
#    get the loop/circle contains the module.port
#    '''
#    def getLoop(self, module, port):
#        pass
#    
#    '''
#    get the pass between module1.port1 and moudle2.port2
#    '''
#    def getPath(self, module1, port1, module2, port2):
#        pass
#   
#class Relation: 
#    '''
#    two element between modules
#    mv stands for (module, port)
#    relation can *not* update later, it is tuple replentaion  
#    '''
#    def __init__(self,port1,port2):
#        '''
#        @param  mv1: (module1,port1)
#        @param  mv2: (module2,port2)  
#        '''
#        self.id = id(self)
#        self.name = port1.module.name + "." + port1.name + "_" + port2.module.name + "." + port2.name  
#        self.port1 = port1
#        self.port2 = port2
#        self.type = 1
#        
#    def update(self):
#        '''
#        update the relation info relatex
#        '''
#        self.name = self.port1.module.name + "." + self.port1.name + "_" + self.port2.module.name + "." + self.port2.name  
#        
#    
#    def toEdge(self,isDict=True):
#        '''
#        transfer relation into relation
#        '''
#        relation = Relation(self.port1,self.port2)
##        relation.setName(self.name)
#        if isDict:
#            return {relation.id:relation}
#        else:
#            return relation
#    
#    def setType(self,type):
#        '''
#        the type of relation, for example:
#        0 stands for the relation is actually not exists
#        1 - mech
#        2 - flow
#        3 - elec         
#        '''
#        self.type = type
#    
#    def setName(self,name):
#        self.name = name
#        
#    def __repr__(self):
#        '''
#        represeng relation's name
#        '''
#        return repr(self.name)
##        return repr(((self.module1,self.port),(self.module2,self.port2)))
